home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
FishMarket 1.0
/
FishMarket v1.0.iso
/
fishies
/
501-525
/
disk_524
/
kamin
/
readme.pl
< prev
next >
Wrap
Text File
|
1992-05-06
|
32KB
|
932 lines
The directory distr contains the code associated with the book
"Programming Languages: An Interpreter-based Approach," by Sam Kamin.
Please report problems to:
Sam Kamin kamin@cs.uiuc.edu
Computer Science Dept. (217) 333-8069
1304 W. Springfield
Urbana, IL 61801
The directory can be obtained either by copying the file distr.tar.Z,
then uncompressing and de-tar'ing, or by copying the files directly
out of the distr directory. If copying the .Z file, be sure to set
the "binary" flag.
CONTENTS OF THIS FILE
=====================
This file contains a number of sections, delimited by a section
name in capital letters and the "=====" underline. The first
several sections are notes about the distribution itself, the
remainder contain code from various contributors to enhance the
interpreters or fix portability bugs.
FILES: A description of each of the files in the distribution.
TESTING THE CODE: How to test and install the interpreters on
Unix systems.
PORTABILITY: Notes about where the interpreters run and where
they need (usually slight) changes.
PROBLEMS: Possible things you might run into when testing/installing
BUGS: Known bugs, mostly minor.
The following sections contain user-contributed code. The first
two relate to VAX VMS systems, the next three to Turbo Pascal, and
the last provides an interpreter-independent load feature. All
are offered, needless to say, without warranty.
FIX TO VAX VMS CODE TO HANDLE LONG OUTPUT LINES
TEST.INTERPS FOR VAX VMS
THE PROCEDURE reader FOR TURBO PASCAL, VERSION 3.0
THE PROCEDURE reader FOR TURBO PASCAL, VERSION 5.5
A FIX FOR THE NON-LOCAL GOTO PROBLEM IN TURBO PASCAL FOR PC'S
INTERPRETER-INDEPENDENT LOAD
A FIX FOR MACINTOSH THINK PASCAL, AND MAYBE OTHERS
FILES
=====
A copy of this file is contained in the distr directory, as well as
a file called TEST.INTERPS, explained later. Aside from these two
files, there are three type of files in the directory:
1. Interpreters (Pascal source files):
chap1.p - Chapter 1
lisp.p - Lisp
apl.p - APL
scheme.p - Scheme
sasl.p - SASL
clu.p - CLU
smalltalk.p - Smalltalk
prolog.p - Prolog
lisp.stack.p - Lisp, using a stack (from Chapter 10)
lisp.ms-gc.p - Lisp, with mark-scan garbage collector (from Chapter 10)
lisp.ss-gc.p - Lisp, with semi-space garbage collector (from Chapter 10)
lisp.refcnt.p - Lisp, with reference-counting (from Chapter 10)
2. Code files, including all code from chapters (plus some test cases
not appearing in text). Note that you may be unable to run these
files as is due to memory limitations. In that case, just split them
up and run the pieces separately. (The Prolog code is given in two
pieces to avoid the problem of redefining predicates.)
code.ch1 - Chapter 1
code.lsp - Lisp
code.apl - APL
code.sch - Scheme
code.ssl - SASL
code.clu - CLU
code.smt - Smalltalk
code1.pro - Prolog, part 1
code2.pro - Prolog, part 2
code.gc.lsp - Garbage-collecting Lisp's (This is the same as code.lsp,
but slightly shorter; there is one example in code.lsp that needs
more memory than the garbage-collecting versions of Lisp allocate
as given.)
3. Output of code files. Use these to check that the interpreters
are running correctly.
code.ch1.o - output from running chap1.p on code.ch1
code.lsp.o - output from running lisp.p on code.lsp
code.apl.o - output from running apl.p on code.apl
code.sch.o - output from running scheme.p on code.sch
code.ssl.o - output from running sasl.p on code.ssl
code.clu.o - output from running clu.p on code.clu
code.smt.o - output from running smalltalk.p on code.smt
code1.pro.o - output from running prolog.p on code1.pro
code2.pro.o - output from running prolog.p on code2.pro
code.stack.o - output from running lisp.stack.p on code.gc.lsp
code.ms-gc.o - output from running lisp.ms-gc.p on code.gc.lsp
code.ss-gc.o - output from running lisp.ss-gc.p on code.gc.lsp
code.refcnt.o - output from running lisp.refcnt.p on code.gc.lsp
TESTING THE CODE
================
When running correctly, the result of executing the interpreter xxx
on file code.xxx should be identical to file code.xxx.o.
On Unix systems, test the interpreters by running the shell procedure
file TEST.INTERPS. It compiles them, runs them on the code.xxx files, and
compares the results to the code.xxx.o files. Before running
TEST.INTERPS, make sure the name of the Pascal compiler ("pc" by
default) is correct. TEST.INTERPS says what output to expect.
It will leave the original files, plus the binaries of
the various interpreters, with names: chap1, lisp, apl, scheme,
sasl, clu, smalltalk, prolog, lisp-stack, lisp-msgc, lisp-ssgc,
and lisp-refcnt.
PORTABILITY
===========
The interpreters are written in standard Pascal, and should run
without change in most systems, especially Unix systems.
They have been tested on the following systems:
Machine and O.S.: SUN 3/60, OS4.0
Compiler: "pc" (dated March, 1988)
Machine and O.S.: Sequent Symmetry, Dynix V3.0.17.7
Compiler: "pascal" (V3.0.1, Silicon Valley Software, c. 1987)
(but see below)
Machine and O.S.: DEC VAX 780, Unix 4.3bsd
Compiler: "pc" (v. 5.1, dated 6/5/85)
Machine and O.S.: DEC VAX 780, VMS 5.3
Compiler: VAX Pascal V4.1
Machine and O.S.: Encore Multimax
Compiler: "pc" (from Oregon Software, v. 1.5, dated 4/27/87)
Machine and O.S.: Pyramid, OSx
Compiler: "pascal" ("man" page dated 1/20/87)
Machine and O.S.: Mac II and SE/30, A/UX
Compiler: VP, from Virginia Tech
(contact Mat Davis, davism@csgrad.cs.vt.edu)
However, the following portability problems have been noted:
Sequent: Occurrences of "integer" should be changed to "longint"
(to give 32-bit integers), at least in smalltalk.p. The
test cases in code.smt will not run correctly with the
default 16-bit integers.
Multimax: The compiler (actually, the loader) reports an
error message on my system, but everything seems to
work fine anyway. (This is probably a local problem.)
VAX VMS (thanks to Mike Berman): The default output buffer
is set too small for some programs. In fact, the
problem only shows up in the Scheme test cases.
A fix is included below. A minor problem is that
the filenames in this distribution are not legal,
as filenames in VMS can contain only one period.
A version of TEST.INTERPS for VMS is given below.
HP9000 (thanks to Tim Budd): The Pascal system automatically
breaks output lines at 256 characters and adds newlines
before closing files. This causes two types of errors
when running the TEST.INTERPS script: (1) Every
test gives a "missing newline" error; (2) The Scheme
test produces a long list of errors, where code.sch.o
has long lines that are broken into two or three lines
by the interpreter (but are otherwise identical). Both
types of errors are benign, and should be ignored.
Turbo-Pascal on IBM PC's and compatibles:
There are two portability problems with this compiler:
(1) It does not support non-local goto's, which are used
in all the interpreters for aborting computations
when errors occur. Since they are only used in
erroneous situations, one solution is just to replace
them by "halt"s; this is ugly, but a correct
solution would be quite involved.
(I have received a solution to this problem,
which is given at the end of this file.)
(2) The treatment of "eoln" is somewhat different from
the Unix compilers, so the input routine "reader"
has to be fixed in all interpreters (it is identical
in all of them). A correct version of reader
for TP is given below (at least, I'm told it works).
PROBLEMS
========
The most likely source of problems when testing the interpreters is running
out of memory. To alleviate the problem, I have made the following
adjustments:
code.lsp: The "quit" has been inserted before
line 414: "(r-e-p-loop '(", the first line of
an 86-line expression whose evaluation uses enormous
amounts of memory.
code.sch: Line 305: "(differentiate '(Dx (+ x c)))" has
been commented out.
code2.pro: The second Prolog file, code2.pro, is not run by
TEST.INTERPS. It is very memory-hungry.
BUGS
====
There are several minor bugs that I am not intending to fix but
which it might be good for you to know about. (The reason I won't
fix them is because I am very determined to keep the code in the book
and the code actually used by students identical; I believe it is
pedagogically important that students not have the feeling that there
are things going on behind their backs.)
1. Normally, blank input is allowed. The interpreters respond to
a newline entered at the -> prompt by ignoring it and issuing another
prompt. However, if the very first thing typed to the interpreter is
a newline, it will not print the prompt. (It will, however, accept
whatever is typed in at that point as legitimate input. In other words,
the only problem is that the prompt is not typed.) (Thanks to Tim Budd
for pointing this out.)
2. The interpreters should respond more gracefully when the "quit" is
omitted from an input file. In most versions of Pascal, the interpreter
aborts with an error message like "eof on input," but in some it loops,
which is really annoying.
3. There are two places, one in clu.p and one in smalltalk.p, where
an incorrect error message is printed. These errors are included in
the book on pages 550 and 563 (see the ERRATA file). I have chosen
to fix these in the distributed code.
4. In the scheme interpreter, the eval function, when applying a
function (in the APEXP case), does not check that the operator is
in fact a function. Thus, an erroneous application like (3 4) will
cause the interpreter to crash rather than print an error message.
To fix this, lines 945-946, which currently read:
else eval :=
applyClosure(op, evalList(args))
should be changed to:
if op^.sxptype = CLOSXP
then eval := applyClosure(op, evalList(args))
else begin
writeln('Attempted to apply a non-closure');
goto 99;
end
(Thanks to Dirk Grunwald for this one.)
FIX TO VAX VMS CODE TO HANDLE LONG OUTPUT LINES
===============================================
The following code was provided by Mike Berman of Glassboro State
College, N.J. Note that it goes at the very beginning of the
top level. Only the Scheme interpreter needs to be changed in
order to run the test cases, but of course you may write programs
with long output in any language.
begin (* scheme main *)
(* modification for VAX Pascal to allow long lines of output *)
(* Mike Berman, Glassboro State College, 10/29/90 *)
(* set the value after record_length:= to whatever you think *)
(* will be adequate for your environment; I chose 2^11 more *)
(* or less arbitrarily. *)
open( output, record_length:=2048 );
(* end of modification *)
TEST.INTERPS FOR VAX VMS
========================
This is also provided by Mike Berman. He would like me to make
it clear that this is strictly a hack and totally unsupported.
However, it might save you some work, so here it is. Note that he
uses filenames that are different from those in this distribution.
In particular, xxx.p becomes xxx.pas (required by VMS
Pascal), and code.xxx.o becomes code-xxx.o (the former is not
a legal filename in VMS).
$! test-interps.com
$! translated from the unix shell script test-interps
$! Michael Berman, Glassboro State College
$! Berman@glassboro.edu
$!
$! There's a crude hack in here -- when you RUN in VMS with the /INPUT=
$! parameter, it runs in the background and the COM file continues to
$! execute. Since the next thing that gets done is the DIFF of the
$! output files, this fails because the program is still running and
$! hasn't finished creating the output files. That's the reason for the
$! WAIT 00:01 lines, which wait for 1 minute. On my system, 1 minute was
$! enough for all but the Smalltalk example, for which 2 minutes was adequate.
$! Obviously, you may need to adjust these if your system is heavily loaded.
$! I'm sure there's a better way to accomplish the same objective.
$!
$! This .com file also uses the convention that the files of the form
$! code.xxx.o (in Unix) have been renamed code-xxx.o, for VMS compatibility.
$!
$echo:==write sys$output
$echo "This file compiles all interpreters, saving binaries, and"
$echo "tests them by running them on files code.xxx (xxx the language name)"
$echo "and comparing the output to the files code-xxx.o."
$echo ""
$echo "The expected output from running this file is the list of messages:"
$echo ""
$echo "Compiling CHAP1; binary is chap1"
$echo "Running CHAP1"
$echo "Number of difference sections found: 0"
$echo "Number of difference records found: 0"
$echo ".... etc. ..."
$echo "Compiling LISP; binary is lisp"
$echo "Running LISP"
$echo ""
$echo "and so on. If the output from any interpreter differs from"
$echo "what it should be, the DIFFERENCES command will report differences"
$echo "in the files."
$echo ""
$echo "See the README file for more information"
$echo ""
$echo "Compiling CHAP1; binary is chap1"
$pascal chap1.pas
$link chap1
$echo "Running CHAP1"
$run/input=code.ch1/output=chap1.out chap1
$wait 00:01
$diff code-ch1.o chap1.out
$del chap1.out;*
$echo "Compiling LISP; binary is lisp"
$pascal lisp.pas
$link lisp
$echo "Running LISP"
$run/input=code.lsp/output=lisp.out lisp
$wait 00:01
$diff code-lsp.o lisp.out
$del lisp.out;*
$echo "Compiling APL; binary is apl"
$pascal apl.pas
$link apl
$echo "Running APL"
$run /input=code.apl/output=apl.out apl
$wait 00:01
$diff code-apl.o apl.out
$del apl.out;1
$echo "Compiling SCHEME; binary is scheme"
$pascal scheme.pas
$link scheme
$echo "Running SCHEME"
$run /input=code.sch/output=scheme.out scheme
$wait 00:01
$diff code-sch.o scheme.out
$del scheme.out;1
$echo "Compiling SASL; binary is sasl"
$pascal sasl.pas
$link sasl
$echo "Running SASL"
$run /input=code.ssl /output=sasl.out sasl
$wait 00:01
$diff code-ssl.o sasl.out
$del sasl.out;1
$echo "Compiling CLU; binary is clu"
$pascal clu.pas
$link clu
$echo "Running CLU"
$run/input=code.clu/output=clu.out clu
$wait 00:01
$diff code-clu.o clu.out
$del clu.out;1
$echo "Compiling SMALLTALK; binary is smalltalk"
$pascal smalltalk.pas
$link smalltalk
$echo "Running SMALLTALK"
$run /input=code.smt/output=smalltalk.out smalltalk
$wait 00:02
$diff code-smt.o smalltalk.out
$del smalltalk.out;1
$echo "Compiling PROLOG; binary is prolog"
$pascal prolog.pas
$link prolog
$echo "Running PROLOG - file 1"
$run/input=code1.pro/output=prolog1.out prolog
$wait 00:01
$diff code1-pro.o prolog1.out
$del prolog1.out;1
$! echo "Running PROLOG - file 2"
$! run /input=code2.pro/output=prolog2.out prolog
$! wait 00:01
$! diff code2-pro.o prolog2.out
$! del prolog2.out;1
$echo "Compiling stacking version of LISP; binary is lisp-stack"
$pascal lisp-stack.pas
$link lisp-stack
$echo "Running stacking version of LISP"
$run/input=code-gc.lsp/output=lisp-stack.out lisp-stack
$wait 00:01
$diff code-stack.o lisp-stack.out
$del lisp-stack.out;1
$echo "Compiling mark-scan version of LISP; binary is lisp-msgc"
$pascal lisp-msgc.pas
$link lisp-msgc
$echo "Running mark-scan version of LISP"
$run/input=code-gc.lsp/output=lisp-msgc.out lisp-msgc
$wait 00:01
$diff code-msgc.o lisp-msgc.out
$del lisp-msgc.out;1
$echo "Compiling semi-space version of LISP; binary is lisp-ssgc"
$pascal lisp-ssgc.pas
$link lisp-ssgc
$echo "Running semi-space version of LISP"
$run/input=code-gc.lsp/output=lisp-ssgc.out lisp-ssgc
$wait 00:01
$diff code-ssgc.o lisp-ssgc.out
$del lisp-ssgc.out;1
$echo "Compiling reference-counting version of LISP; binary is lisp-refcnt"
$pascal lisp-refcnt.pas
$link lisp-refcnt
$echo "Running reference-counting version of LISP"
$run /input=code-gc.lsp /output=lisp-refcnt.out lisp-refcnt
$wait 00:01
$diff code-refcnt.o lisp-refcnt.out
$del lisp-refcnt.out;1
THE PROCEDURE reader FOR TURBO PASCAL, VERSION 3.0
==================================================
Simply replace the reader procedure in all interpreters by the
following. Together with replacing all occurrences of "goto 99"
by "halt", the interpreters should run in TP.
(* reader - read char's into userinput; be sure input not blank *)
procedure reader;
(* readInput - read char's into userinput *)
procedure readInput;
var c: char;
(* nextchar - read next char - filter tabs and comments *)
procedure nextchar (var c: char);
begin
read(con,c);
if c = chr(TABCODE)
then c := ' '
else if c = COMMENTCHAR
then begin
while (c<>chr(13)) do read(con,c);
read(con,c);
c := ' ';
end
end; (* nextchar *)
(* readParens - read char's, ignoring newlines, to matching ')' *)
procedure readParens;
var
parencnt: integer; (* current depth of parentheses *)
c: char;
begin
parencnt := 1; (* '(' just read *)
repeat
nextchar(c);
if (c=chr(13)) then
begin
read(con,c);
write(PROMPT2);
c:=' ';
end;
pos := pos+1;
if pos = MAXINPUT
then begin
writeln('User input too long');
halt
end;
userinput[pos] := c;
if c = '(' then parencnt := parencnt+1;
if c = ')' then parencnt := parencnt-1;
until parencnt = 0
end; (* readParens *)
begin (* readInput *)
write(PROMPT);
pos := 0;
repeat
pos := pos+1;
if pos = MAXINPUT
then begin
writeln('User input too long');
halt
end;
nextchar(c);
if (c=chr(13)) then read(con,c);
userinput[pos] := c;
if userinput[pos] = '(' then readParens
until c=chr(10);
inputleng := pos;
userinput[pos+1] := COMMENTCHAR (* sentinel *);
end; (* readInput *)
begin (* reader *)
repeat
readInput;
pos := skipblanks(1);
until pos <= inputleng (* ignore blank lines *)
end; (* reader *)
THE PROCEDURE reader FOR TURBO PASCAL, VERSION 5.5
==================================================
Simply replace the reader procedure in all interpreters by the
following. Together with replacing all occurrences of "goto 99"
by "halt", the interpreters should run in TP. (Thanks to David
Maharry of Wabash College in Indiana for this code.)
(* Chapter 1 interpreter from Kamin, modified for Turbo Pascal V5.5
using new Reader procedure
By: David E. Maharry
Wabash College
Date: June 6, 1990
*)
(* reader - read char's into userinput; be sure input not blank *)
procedure reader;
(* readInput - read char's into userinput *)
procedure readInput;
const LINEMAX = 80;
type line_type = String[LINEMAX];
var line : line_type;
parencount : INTEGER;
inputdone : BOOLEAN;
i: INTEGER;
(* checkForComment - function to look and find commentchar in line *)
function checkforcomment(line : line_type):integer;
(* returns 0 if no comment, else position of commentchar *)
var found : boolean;
i : integer;
begin
found := FALSE;
i := 0;
while (i < length(line)) and (not found) do
begin
i := i + 1;
found := (line[i] = COMMENTCHAR)
end;
if found then checkforcomment := i
else checkforcomment := 0
end; (* checkforcomment *)
(* filters out tabs and comments *)
procedure filter ( var line : line_type );
var temp : line_type;
i : INTEGER;
begin
temp := '';
for i := 1 to length(line) do
if line[i] = chr(TABCODE)
then temp := temp + ' '
else temp := temp + line[i];
i := checkforcomment(line);
if i <> 0 then line := copy(temp, 1, i-1)
else line := temp
end; (* filter *)
(* matches left and right parens in line *)
function countparen(line : line_type): INTEGER;
var i, count : INTEGER;
begin
count := 0;
for i := 1 to length(line) do
begin
if line[i] = '(' then count := count + 1
else if line[i] = ')' then count := count - 1;
end;
countparen := count
end; (* countparen *)
begin (* readInput *)
parencount := 0;
inputleng := 0;
repeat
if inputleng = 0 then write(PROMPT)
else write(PROMPT2);
readln(line);
filter(line);
parencount := parencount + countparen(line);
if parencount < 0 then begin
writeln('Invalid parentheses.');
halt(1)
end;
inputdone := (parencount = 0);
if inputleng + length(line) >= MAXINPUT
then begin
writeln('User input too long');
halt(1)
end;
if inputleng > 0 then
(* puts a space between input lines *)
begin
inputleng := inputleng + 1;
userinput[inputleng] := ' '
end;
for i := 1 to length(line) do
begin
inputleng := inputleng + 1;
userinput[inputleng] := line[i]
end
until inputdone;
userinput[inputleng+1] := COMMENTCHAR (* sentinel *)
end; (* readInput *)
begin (* reader *)
repeat
readInput;
pos := skipblanks(1);
until pos <= inputleng; (* ignore blank lines *)
end; (* reader *)
A FIX FOR THE NON-LOCAL GOTO PROBLEM IN TURBO PASCAL FOR PC'S
=============================================================
I have received this fix from Norm Neff of Trenton State College
(neff@pilot.njin.net). He says it should work on TP versions 4.0
and up, but adds "it's been tested [on TP 5.0], but not class-
tested."
(* **BEGIN*** DECL99.PAS Declarations for goto ************** *)
(* Steps to enable nonlocal goto, TP v. 5.0
1. Insert these declarations, first in the main program's decl part
2. Insert contents of DEF99.PAS in the main program's stmt part,
immediately prior to the statement labeled 99.
3. Change each 'goto 99' statement of the original program to the
procedure call 'goto99'. Also, use 'goto99' 's in the reader.
Prepared by
Norman Neff
Computer Science Department
Trenton State College
Hillwood Lakes CN550
Ewing Township, NJ 08625-0550
neff@pilot.njin.net *)
var cs99,ss99,ds99,ip99,sp99,bp99:integer;(*must be global*)
procedure goto99;
var Dslocal:integer;
destination: record
ip,cs: integer
end;
begin (* Restores DS , CS, IP *)
DSlocal := ds99;
destination.ip := ip99;
destination.cs := cs99;
inline (* ADDRESSING wrt SS:BP *)
($8E/$9E/Dslocal/ (* MOV DS,DsLocal[BP] *)
$FF/$AE/destination ); (* JMP FAR ( destination[BP]) *)
end;
procedure SaveIP(var ipv:integer);
(* ipv := return address *)
var iphold:integer;
begin
inline (* ADDRESSING wrt SS:BP *)
( $53/ (* PUSH BX *)
$8B/$9E/$02/$00/ (* MOV BX, 2[BP] *)
$89/$9E/IPHOLD/ (* MOV iphold[BP],BX *)
$5B (* POP BX *) );
ipv := iphold;
end;
(* **END***** DECL99.PAS Declarations for goto ************** *)
(* *****BEGIN**** DEF99.PAS *************************** *)
(* To be inserted immediately before the statement labeled 99
in the program's top level *)
inline (* save state *)
($89/$2E/BP99/ (* MOV BP99,BP *)
$89/$26/SP99/ (* MOV SP99,SP *)
$8C/$16/SS99/ (* MOV SS99,SS *)
$8C/$1E/DS99/ (* MOV DS99,DS *)
$8C/$0E/CS99); (* MOV CS99,CS *)
SaveIP(ip99);
(* call to goto99 jumps to this entry point *)
inline (* complete restoring state *)
($8E/$16/SS99/ (* MOV SS,SS99 *)
$8B/$26/SP99/ (* MOV SP,SP99 *)
$8B/$2E/BP99); (* MOV BP,BP99 *)
(* ENTRY POINT 99 FOLLOWS : *)
(* *****END****** DEF99.PAS ************************ *)
INTERPRETER-INDEPENDENT LOAD
============================
The following is from Paul Mullins of Youngstown State University.
I tried it and it worked fine for me. Remember that before using it,
you have to compile the "frontend.c" file (naming the program "frontend")
and modify the variable "$INTERPS" to give the directory containing
the interpreters. Also, when run with this system, if you terminate
with "quit", you have to enter two carriage-returns before the program
will stop; you can also terminate with a single CTRL-D.
I might point out that on Unix systems a cheap way to load a single
file at the beginning of an interpreter session, followed by input
from the terminal, is this:
cat <input> - | <interpreter>
in which the file <input> is the program to be loaded (without a
"quit" at the end!). Again, you will find you have to enter
carriage-return twice at the end of the session after typing "quit".
Alternatively, you can create a file "quitfile" containing the
single line "quit", and start it like this:
cat <input> - quitfile | <interpreter>
in which case the session is terminated by entering CTRL-D.
(Gary Leavens of Iowa State Univ. points out that this has to be
done slightly differently on HP-UX, and possibly on other systems,
because cat buffers its input. On those systems, you should say:
cat -u <input> - | <interpreter>
)
The remainder of this section is quoted directly from Professor Mullins:
The code which follows is provided without warranty or copyright. Use it
or not as you see fit. Sample session:
$ fe prolog in1 in2
reading in1
done reading in1
reading in2
done reading in2
-> > > > satisfied
-> > > not satisfied
-> load in3
reading in3
done reading in3
->
satisfied
-> ^d
$
----------------------------------------------------------------------------
Paul M. Mullins mullins@macs.ysu.edu
Dept of Mathematical FC137501@YUB
and Computer Sciences fc137501@ysub.ysu.edu
Youngstown State University
Youngstown, OH 44555-0001 (216) 742-3796
SHAR FILE - feed to sh
-------------------------- cut here ------------------------------------------
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of shell archive."
# Contents: fe frontend.c
# Wrapped by mullins@ysumax on Wed Nov 28 13:20:34 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'fe' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'fe'\"
else
echo shar: Extracting \"'fe'\" \(793 characters\)
sed "s/^X//" >'fe' <<'END_OF_FILE'
X#! /bin/sh
X# NOT copyright by Paul Mullins
X# You may distribute, modify, remove my name, ...
X# This is a front end for various interpreters which are located
X# in $INTERPS. It invokes a C frontend which allow command files
X# to be sent to the interpreter. A list of files to be preloaded
X# may be specified on the command line.
X
X# site dependent
XINTERPS=distr
X
X# check argument count
Xcase $# in
X0) echo usage: $0 interp_name \[file_list\]; exit 0;;
X*) ;;
Xesac
X
X# Modify CMD to the string most appropriate for the named interpreter
Xcase $1 in
Xchap1 | lisp | apl | scheme | sasl | clu | smalltalk) CMD=load;;
Xprolog) CMD=consult;;
Xlisp-msgc | lisp-ssgc | lisp-stack) CMD=load;;
X*) echo unknown interpreter $1; exit 0;;
Xesac
X
XINT=$1
Xshift
X
X# invoke it
X$INTERPS/frontend $CMD $@ | $INTERPS/$INT
END_OF_FILE
if test 793 -ne `wc -c <'fe'`; then
echo shar: \"'fe'\" unpacked with wrong size!
fi
chmod +x 'fe'
# end of 'fe'
fi
if test -f 'frontend.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'frontend.c'\"
else
echo shar: Extracting \"'frontend.c'\" \(1098 characters\)
sed "s/^X//" >'frontend.c' <<'END_OF_FILE'
X/* invocation: frontend string [file_list] */
X/* NOT copyright Paul M. Mullins
X * You may copy, modify, remove my name, ...
X */
X#include <stdio.h>
X#include <ctype.h>
X#define MAXLINE 1024
X/* cmd is a prefix string which is followed by a blank and a file name */
X/* uses brain damaged approach - leading blanks aren't stripped, etc */
Xchar *cmd;
X
Xvoid fileread (fn)
Xchar *fn;
X{
XFILE *fp, *fopen();
Xint c;
X
X fprintf(stderr,"\tReading file %s\n", fn);
X if ((fp=fopen(fn,"r"))==NULL) {
X fprintf(stderr,"\tRead failed\n");
X exit(1);
X }
X while ((c=getc(fp))!=EOF)
X putchar(c);
X fflush(stdout);
X fprintf(stderr,"\tDone reading %s\n",fn);
X}
X
Xmain (argc, argv)
Xint argc;
Xchar **argv;
X{
Xint i;
Xchar line[MAXLINE];
X
X if (argc < 2) {
X fprintf(stderr,"usage: %s cmd_string [file_list]\n",argv[0]);
X exit (1);
X }
X else cmd = argv[1];
X
X for (i=2; i<argc; i++)
X fileread(argv[i]);
X
X while (gets(line) != NULL) {
X if (strncmp(cmd,line,strlen(cmd))==0) {
X for (i=strlen(cmd); isspace(line[i]) && (i < MAXLINE); i++);
X fileread (line+i);
X }
X else
X printf("%s\n",line);
X fflush(stdout);
X }
X printf("quit\n");
X}
END_OF_FILE
if test 1098 -ne `wc -c <'frontend.c'`; then
echo shar: \"'frontend.c'\" unpacked with wrong size!
fi
# end of 'frontend.c'
fi
echo shar: End of shell archive.
exit 0
A FIX FOR MACINTOSH THINK PASCAL, AND MAYBE OTHERS
==================================================
Walt Leipold (leipolw%esvax@dupont.com) points out that my input
code (procedure nextchar) assumes you can "read" (as opposed to
"readln") past end-of-line. He has found that Symantec's Think
Pascal for the Macintosh does not allow this. He suggests
replacing nextchar by the following code. The change should
be benign in any case, and may apply to other Pascal's, though
I don't know any examples.
(* nextchar - read next char - filter tabs and comments *)
procedure nextchar (var c: char);
begin
if eoln then begin
readln;
c := ' '
end
else begin
read(c);
if c = chr(TABCODE) then
c := ' '
else if c = COMMENTCHAR then begin
while not eoln do
read(c);
c := ' '
end
end;
end; (* nextchar *)